﻿package org.kolonitsky.alexey.algorithm.astro
{
    import flash.display.Sprite;

   
    public class Astro extends Sprite
    {
        private var latitude:Number = 53.917;
        private var latitudeMin:Number = 0.0;
        private var latitudeSec:Number = 0.0;
        
        private var longetude:Number = 27.55;
        private var longetudeMin:Number = 0.0;
        private var longetudeSec:Number = 0.0;
        
        private var ewv:String = "East";
        private var nsv:String = "North";
        
        /** morining twilight angle **/
        private var twr:Number = -7;
        /** evening twilight angle **/
        private var tws:Number = -7;
        
        private var mday:String;
        
        private var _date:Date;
        
        private var k:Number = Math.PI / 180.0;
        
        public var midday:Date;
        public var eveningTwilight:Date;
        public var sunset:Date;
        public var sunrise:Date;
        public var morningTwilight:Date;
        
        
        public function Astro()
        {
        }
        
        private function ut(h:Number, m:Number, z:Number):Number { return (h - z + m / 60) }
        
        private function sin(degree:Number):Number { return Math.sin(degree * k) }
        
        private function cos(degree:Number):Number {return Math.cos(degree * k)}
        
        private function asin(r:Number):Number {return Math.asin(r)}
        
        private function atan2(x:Number, y:Number):Number {return Math.atan2(x, y)}
        
        private function tan(degree:Number):Number {return Math.tan(degree * k)}
        
        
        public function get date():Date
        {
            return _date
        }
        
        public function set date(value:Date):void
        {
            this._date = value;
            eveningTwilight = new Date(_date.time);
            sunset = new Date(_date.time);
            sunrise = new Date(_date.time);
            morningTwilight = new Date(_date.time);
            midday = new Date(_date.time);
        }
         
        /**
         * Day number. 
         * The day number is used to compute values of all time varying quantities. 
         * It is a measure of the number of days, hours, minutes, and seconds since 
         * epoch 1 January 2000.
         **/
        private function jd(y:Number, m:Number, d:Number, u:Number):Number
        {
            return (367 * y) - Math.floor((7/4)*(Math.floor((m+9)/12)+y)) + Math.floor(275*m/9) + d - 730531.5 + (u/24) 
        }
        
        
        public function azimuth(ye:Number, mo:Number, da:Number, ho:Number, mi:Number, zo:Number):Number
        {
            var uu:Number = ut(ho,mi,zo);
            var jj:Number = jd(ye,mo,da,uu);
            var T:Number = jj/36525;
            var M:Number = 357.5291+35999.0503*T-0.0001559*T*T-0.00000045*T*T*T
            M=M % 360
            var Lo:Number = 280.46645+36000.76983*T+0.0003032*T*T
            Lo=Lo % 360
            var DL:Number = (1.9146-0.004817*T-0.000014*T*T)*sin(M)+(0.019993-0.000101*T)*sin(2*M)+0.00029*sin(3*M)
            var L:Number = Lo+DL
            var eps:Number = 23.43999-0.013*T
            var delta:Number = (1/k) * asin(sin(L) * sin(eps))
            var RA:Number = (1/k) * atan2(cos(eps) * sin(L), cos(L))
            RA=(RA+360) % 360
            var GMST:Number = 280.46061837+360.98564736629*jj+0.000387933*T*T-T*T*T/38710000
            GMST=(GMST+360) % 360
            var LMST:Number = GMST + longetude
            var H:Number = LMST - RA
            var eqt:Number = (Lo - RA) * 4
            var azm:Number = (1/k) * atan2(-sin(H), cos(latitude) * tan(delta) - sin(latitude) * cos(H))
            azm=(azm+360) % 360
            return azm
        }
        
        
        public function altitude(ye:Number, mo:Number, da:Number, ho:Number, mi:Number, zo:Number):Number
        {
            var uu:Number = ut(ho, mi, zo);
            var jj:Number = jd(ye, mo, da, uu);
            var T:Number = jj / 36525;
            var M:Number = 357.5291+35999.0503*T-0.0001559*T*T-0.00000045*T*T*T
            M=M % 360
            var Lo:Number = 280.46645+36000.76983*T+0.0003032*T*T
            Lo=Lo % 360
            var DL:Number = (1.9146-0.004817*T-0.000014*T*T)*sin(M)+(0.019993-0.000101*T)*sin(2*M)+0.00029*sin(3*M)
            var L:Number = Lo+DL
            var eps:Number = 23.43999 - 0.013 * T
            var delta:Number = (1/k) * asin( sin(L) * sin(eps) )
            var RA:Number = (1/k)*atan2(cos(eps)*sin(L),cos(L))
            RA=(RA+360) % 360
            var GMST:Number = 280.46061837+360.98564736629*jj+0.000387933*T*T-T*T*T/38710000
            GMST=(GMST+360) % 360
            var LMST:Number = GMST + longetude
            var H:Number = LMST - RA
            var eqt:Number = (Lo - RA) * 4
            var alt:Number = (1/k) * asin(sin(latitude) * sin(delta) + cos(latitude) * cos(delta) * cos(H))
            return alt;
        }
        
        
        /**
         *
         **/
        public function sunpos():void
        {
            longetude = longetude + longetudeMin / 60;
            latitude = latitude + latitudeMin / 60;
            
            var aa:Number = 180.0
            if (ewv=="West")
            {
                longetude = -longetude;
            }
            if (nsv=="South")
            {
                latitude = -latitude; 
                aa=0.0;
            }
            
            var ye:Number = _date.fullYear;
            var mo:Number = _date.month +1;
            var da:Number = _date.date;
            var ho:Number = _date.hours;
            var mi:Number = _date.minutes;
            var zo:Number = -_date.timezoneOffset / 60;
            
            var h1:Number = 0;
            var m:Number = 0;
            var alt1:Number = altitude(ye,mo,da,h1,m,zo);
            var azm1:Number = azimuth(ye,mo,da,h1,m,zo);
            
            var s:Number = -0.8333;
         
            // find midday interval
            for (var h:Number=0; h < 24; h++)
            {
                var h2:Number = h
                var azm2:Number = azimuth(ye,mo,da,h2,m,zo)
                if (azm1 <= 180 && azm2 >= 180)
                {
                    var ha1:Number = h1
                    var ha2:Number = h2
                }
                h1 = h2
                azm1 = azm2
            }
         
            // find exact midday time
            var mino:Number = 1.0;
            
            for (h=ha1; h < ha2; h++)
            {
                for (m=0; m < 60; m++)
                {
                    var azmo:Number = azimuth(ye,mo,da,h,m,zo)
                    var dfo:Number = Math.abs(aa - azmo)
                    if (dfo <= mino)
                    {
                        mino = dfo
                        midday.hours = h
                        midday.minutes = m
                    }
                }
            }
            
            var altnoon:Number = altitude(ye, mo, da, midday.hours, midday.minutes, zo);
            
            mday = altnoon < s ? "nigth" : ""
         
            var mintwr:Number = 0.1;
            var minr:Number = 0.1
         
            for (h=0; h <= midday.hours; h++)
            {
                for (m=0; m < 60; m++)
                {
                    if (60 * h + m < 60 * midday.hours + midday.minutes)
                    {
                        var altr:Number = altitude(ye, mo, da, h, m, zo);
                        var dftwr:Number = Math.abs(twr - altr);
                  
                        if (dftwr <= mintwr) 
                        {
                            mintwr = dftwr;
                            morningTwilight.hours = h;
                            morningTwilight.minutes = m;           
                        }
                  
                        if (altnoon > s)
                        {
                            var dfr:Number = Math.abs(s - altr)
                            if (dfr <= minr) 
                            {
                                minr = dfr;
                                sunrise.hours = h;
                                sunrise.minutes = m;
                            }
                        }
                    }
                }
            }
         
            var mins:Number = 0.1;
            var mintws:Number = 0.1;
         
            for (h = midday.hours; h < 24; h++)
            {
                for (m = 0; m < 60; m++)
                {
                    if (60 * h + m >= 60 * midday.hours + midday.minutes)
                    {
                        var alts:Number = altitude(ye, mo, da, h, m, zo);
                        
                        if(altnoon > s)
                        {
                            var dfs:Number = Math.abs(s - alts)
                            if (dfs <= mins) 
                            {
                                mins = dfs;
                                sunset.hours = h;
                                sunset.minutes = m;
                            }
                        }
                  
                        var dftws:Number = Math.abs(tws - alts)
                        if (dftws <= mintws) 
                        {
                            mintws = dftws;
                            eveningTwilight.hours = h;
                            eveningTwilight.minutes = m;
                        }
                    }
                }
            }
        }
        
        
        /**  **/
        public function output():void
        {
            var ye:Number = _date.fullYear;
            var mo:Number = _date.month +1;
            var da:Number = _date.date;
            var ho:Number = _date.hours;
            var mi:Number = _date.minutes;
            var zo:Number = -_date.timezoneOffset / 60;

            // Восход и Заход Солнца, автор (C) 2001, Senol Gulgonul
            // Скрипт размещен на сайте http://randewy.narod.ru
            trace("___________________________________________");
            trace("Дата: " + _date);
            trace("Минск: " + 
                "\n\t" + latitude.toFixed(3) + "° " + (nsv == "North" ? "Северной широты" : "Южной широты") +
                "\n\t" + longetude.toFixed(3) + "° " + (ewv == "East" ? "Восточной долготы" : "Западной долготы"));
            trace("Сумерки: утренние " + twr + "°, вечерние " + tws + "°");
            trace("Высота:" + altitude(ye, mo, da, ho, mi, zo).toFixed(3) + "°");
            trace("Азимут:" + azimuth(ye, mo, da, ho, mi, zo).toFixed(3) + "°\n");
            
            trace("Сумерки утренние " + morningTwilight);
            trace("Восход " + sunrise);
            trace("Кульминация " + midday + " " + mday);
            trace("Заход " + sunset);
            trace("Сумерки вечерние " + eveningTwilight + "\n\n");
        }
    }
}